#include <lore/assembler.hpp>
#include <lore/program.hpp>

#define BOOST_TEST_MODULE AssemblerTestModule

#include <boost/test/included/unit_test.hpp>

BOOST_AUTO_TEST_SUITE( AssemblerTestSuite )

BOOST_AUTO_TEST_CASE( TestAdda )
{
	const int test_times = 50;

	for (int i(0) ; i < test_times ; ++i)
	{
		int a(::rand());
		int b(::rand());

		std::string adda_program(
			"? ADDa " + boost::lexical_cast<std::string>(a) + " " + boost::lexical_cast<std::string>(b) + " 32\n"
			"32 EXIT ? ? ?\n"
		);

		Program p(assemble(adda_program));
		Program::ExecutionResult er(p.execute());

		assert(!er.error());
	}
}


BOOST_AUTO_TEST_CASE( TestAddb )
{
	const int test_times = 50;

	for (int i(0) ; i < test_times ; ++i)
	{
		int a(::rand());
		int b(::rand());

		std::string addb(
			"? ADDb " + boost::lexical_cast<std::string>(a) + " " + boost::lexical_cast<std::string>(b) + " 93\n"
			"93 ADDa 0 ? 43\n"
			"43 EXIT ? ? ?\n"
		);

		Program p(assemble(addb));
		Program::ExecutionResult er(p.execute());

		BOOST_CHECK(!er.error());
		BOOST_CHECK_EQUAL(er.return_code(), a+b);
	}
}


BOOST_AUTO_TEST_CASE( QuestionMarkDefine )
{
	std::string assembly(
		"? ADDa 0 1 ex\n"
		"? NOOP 0 0 0\n"
		"(ex=?) EXIT -1 0 0\n"
		"? NOOP 0 0 0\n"
	);

	Program p(assemble(assembly));
	Program::ExecutionResult er(p.execute());

	BOOST_CHECK(!er.error());
	BOOST_CHECK_EQUAL(er.return_code(), 1);
}

BOOST_AUTO_TEST_CASE( TestPrettyPrint )
{
	// a pretty printed program should be assemblable

	std::string assembly("? EXIT 44 ? ?\n");


	Program p1(assemble(assembly));
	Program p2(assemble(p1.disassemble()));

	BOOST_CHECK_EQUAL(p1.execute(), p2.execute());
}

BOOST_AUTO_TEST_SUITE_END()
